// 关于 C++ 中 protected 成员变量的使用
// Effective C++ 条款 22："将成员变量声明为 private"，
// 那么什么变量应该设计为 protected。

// protected 成员变量的适用场景
// 在现代 C++ 设计中，protected 成员变量应该非常谨慎使用，因为它们会导致基类与派生类之间的紧耦合。
// 但确实存在一些适合使用 protected 的情况：

// 1. 派生类特有的实现细节接口 当某些成员变量表示的是派生类实现时必须访问的内部状态，但这些状态不应该暴露给外部客户端时：
class Shape
{
protected:
    // 派生类需要直接访问的绘图状态
    DrawingContext *drawingContext;

private:
    Color fillColor;
    LineStyle lineStyle;

public:
    void setFillColor(const Color &color);
    Color getFillColor() const;
    // 其他公共接口...
};

class Circle : public Shape
{
public:
    void draw() override
    {
        // 直接访问 drawingContext 而不需要通过额外的方法调用
        drawingContext->beginDraw();
        // 绘制圆形...
        drawingContext->endDraw();
    }
};

// 2. 性能关键路径上的数据
// 在极少数情况下，当性能至关重要且通过访问器方法会引入不可接受的开销时：
class RealTimeSignalProcessor
{
protected:
    // 高性能处理需要直接访问的缓冲区
    float *signalBuffer;
    size_t bufferSize;

private:
    // 其他配置参数
    int sampleRate;
    bool filterEnabled;

public:
    // 公共接口...
};

class FFTProcessor : public RealTimeSignalProcessor
{
public:
    void processSignal()
    {
        // 直接访问缓冲区以避免额外的函数调用开销
        for (size_t i = 0; i < bufferSize; ++i)
        {
            // 高性能处理...
        }
    }
};

// 3. 框架设计中的扩展点
// 在框架设计中，某些变量可能作为预定义的扩展点：
class PluginFramework
{
protected:
    // 插件可以访问的扩展点
    PluginRegistry *registry;
    ConfigurationManager *configManager;

private:
    // 内部实现细节
    std::vector<Plugin *> loadedPlugins;

public:
    // 公共接口...
};

class CustomPlugin : public PluginFramework
{
public:
    void initialize() override
    {
        // 直接访问框架提供的扩展点
        registry->registerFeature("MyFeature", this);
        auto config = configManager->getPluginConfig("CustomPlugin");
        // 初始化插件...
    }
};

// 更好的替代方案
// 在大多数情况下，应该避免使用 protected 成员变量，而是采用以下替代方案：

// 1. Protected 访问器方法
class Base
{
private:
    int data;

protected:
    // 为派生类提供受控访问
    int &getData() { return data; }
    const int &getData() const { return data; }

public:
    // 公共接口...
};
// 2. Protected 成员函数而非变量
class UIComponent
{
private:
    Rect bounds;
    Color backgroundColor;

protected:
    // 提供派生类可能需要的功能性接口
    void invalidateRegion(const Rect &region);
    bool isVisible() const;
    Rect getClientArea() const;

public:
    // 公共接口...
};

// 3. 使用 CRTP (奇异递归模板模式)
// 对于高性能场景，可以考虑使用 CRTP 来避免虚函数调用开销，同时保持良好的封装：
template <typename Derived>
class Base
{
private:
    int data;

protected:
    // 允许派生类以静态多态方式访问数据
    int &getData() { return data; }
    const int &getData() const { return data; }

    // 派生类可以访问的实用方法
    void commonImplementation()
    {
        // 使用 data 的通用实现...
    }
};

class Derived : public Base<Derived>
{
public:
    void process()
    {
        // 静态多态访问，编译时解析，没有虚函数开销
        int &value = this->getData();
        // 处理...
        this->commonImplementation();
    }
};

// 总结与最佳实践
// 1.默认使用 private：成员变量默认应该是 private 的
// 2.谨慎使用 protected：只在确实需要时才使用 protected
// 3.优先使用访问器：如果派生类需要访问基类状态，提供 protected 访问器方法
// 4.考虑设计意图：使用 protected 成员时，明确记录其目的和使用约定
// 5.接口与实现分离：尽量保持接口与实现的分离，即使在基类和派生类之间
// 最终，protected 成员变量的使用应该是经过深思熟虑的设计决策，而不是默认选择。在大多数情况下，良好的面向对象设计会倾向于通过方法而不是直接访问变量来实现基类与派生类之间的交互。
